﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;

namespace BitcoinLibrary
{
    /**
    * This message is a reference or pointer to an output of a different transaction.
    */
    public class TransactionOutPoint : Message /*implements Serializable */{
        private static readonly long serialVersionUID = -6320880638344662579L;

        /** Hash of the transaction to which we refer. */
        internal byte[] hash;
        /** Which output of that transaction we are talking about. */
        internal long index;

        // This is not part of Bitcoin serialization. It's included in Java serialization.
        // It points to the connected transaction.
        internal Transaction fromTx;

        public TransactionOutPoint(NetworkParameters param, long index, Transaction fromTx)
            : base(param)
        {
            this.index = index;
            if (fromTx != null)
            {
                this.hash = fromTx.getHash().hash;
                this.fromTx = fromTx;
            }
            else
            {
                // This happens when constructing the genesis block.
                hash = new byte[32]; // All zeros.
            }
        }

        /** Deserializes the message. This is usually part of a transaction message. */
        public TransactionOutPoint(NetworkParameters param, byte[] payload, int offset)
            : base(param, payload, offset)
        {
        }

        public override void parse()
        {
            hash = readHash();
            index = readUint32();
        }

        public void bitcoinSerializeToStream(Stream stream)
        {
            Debug.Assert(hash.Length == 32);
            stream.Write(Utils.reverseBytes(hash), 0, hash.Length);
            Utils.uint32ToByteStreamLE(index, stream);
        }

        /**
        * If this transaction was created using the explicit constructor rather than deserialized,
        * retrieves the connected output transaction. Asserts if there is no connected transaction.
        */
        public TransactionOutput getConnectedOutput()
        {
            if (fromTx == null) return null;
            return fromTx.outputs[(int)index];
        }

        /**
        * Returns the pubkey script from the connected output.
        */
        internal byte[] getConnectedPubKeyScript()
        {
            byte[] result = getConnectedOutput().getScriptBytes();
            Debug.Assert(result != null);
            Debug.Assert(result.Length > 0);
            return result;
        }

        /**
        * Convenience method to get the connected outputs pubkey hash.
        */
        internal byte[] getConnectedPubKeyHash()
        {
            return getConnectedOutput().getScriptPubKey().getPubKeyHash();
        }
    }

}
